/*
 * Copyright 2014 Graham Smith
 */
package uk.co.wobblycogs.vegas.riff;

import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;

/**
 *
 * @author Graham Smith
 */
public class RIFFUtilities {

	private final static char[] HEX_CHARS = "0123456789ABCDEF".toCharArray();

	private RIFFUtilities() {
	}

	/**
	 * Moves the buffer forward or backward count bytes.
	 *
	 * @param bb
	 * @param count
	 */
	public static void move(ByteBuffer bb, int count) {
		bb.position(bb.position() + count);
	}

	public static String bytesToHex(byte[] bytes) {
		char[] hexChars = new char[bytes.length * 2];
		for (int j = 0; j < bytes.length; j++) {
			int v = bytes[j] & 0xFF;
			hexChars[j * 2] = HEX_CHARS[v >>> 4];
			hexChars[j * 2 + 1] = HEX_CHARS[v & 0x0F];
		}
		return new String(hexChars);
	}

	/**
	 * Makes a best effort to show a full RIFFObject tree.
	 *
	 * @param obj
	 * @return
	 */
	public static String toString(RIFFObject obj) {
		if (!(obj instanceof RIFFList)) {
			return obj.toString();
		} else {
			StringBuilder builder = new StringBuilder();
			printTree(((RIFFList) obj), builder, 0);
			return builder.toString();

		}
	}

	private static void printTree(RIFFList list, StringBuilder builder, int indent) {
		indent++;
		builder.append(list.toString());
		for (RIFFObject r : list.getChildren()) {
			if (r instanceof RIFFChunk) {
				builder.append(System.lineSeparator());
				for (int i = 0, n = indent; i < n; i++) {
					builder.append("    ");
				}
				builder.append(r.toString());
			} else {
				builder.append(System.lineSeparator());
				for (int i = 0, n = indent; i < n; i++) {
					builder.append("    ");
				}
				printTree(((RIFFList) r), builder, indent);
			}
		}
	}

	/**
	 * Finds all resources with the given type in the project. The order of the
	 * resources returned is not defined.
	 *
	 * @param project
	 * @param found
	 * @param riffType
	 */
	public static void find(RIFFObject root, List<RIFFObject> found, byte[] riffType) {
		if (Arrays.equals(root.getRawType(), riffType)) {
			found.add(root);
		}

		for (RIFFObject child : root.getChildren()) {
			find(child, found, riffType);
		}
	}

	/**
	 * Extracts a string from the given buffer starting at the current position
	 * and running for the given number of bytes. This assumes that the
	 * characters will be two byte and the that buffer has been set to the
	 * correct endianness.
	 *
	 * @param bb
	 * @param length
	 * @return
	 */
	public static String getString(ByteBuffer bb, int byteCount) {
		char[] text = new char[byteCount / 2];
		for (int i = 0, n = text.length; i < n; i++) {
			text[i] = bb.getChar();
		}
		return new String(text).trim();
	}
}
